//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Linq;

using ProjectBase.Core;

using $prjsn$.Entity;
using $prjsn$.Common;
using $prjsn$.Common.Validation;
using $prjsn$.Common.Data;
using ProjectBase.Core.Service;

namespace $safeprojectname$
{
    public class FieldObjectValidator<TEntity, TDao, TBusinessObject> : EntityValidatorBase<TEntity, int, TDao>
        where TEntity : FieldObject
        where TDao : class, IFieldObjectDao<TEntity>
        where TBusinessObject : class, IBusinessObject
    {
        protected override void Init(RuleCollection<TEntity> rules)
        {
            // value types
            rules.For(entity => entity.ColumnName).RequireMaxLength(150).ApplyOnServer();
            rules.For(entity => entity.TableName).RequireLengthBetween(1, 150).ApplyOnServer();
            rules.For(entity => entity.DisplayName).RequireLengthBetween(1, 150).ApplyOnServer();

            rules.For(entity => entity.DataType).RequireLengthBetween(1, 150);

            rules.For(entity => entity.MaxValue).RequireMaxLength(150);
            rules.For(entity => entity.MinValue).RequireMaxLength(150);

            rules.For(entity => entity.Length).RequireValueBetween(1, 2000).AllowNull();
            rules.Assure(StringFieldHasLength);

            // unique
            rules.For(entity => entity.PropertyName).RequireLengthBetween(1, 150).BreakOnError();
            rules.IsUnique(entity => Dao.Find(entity.ID,
                 new FieldFilter
                 {
                     PropertyNameExact = entity.PropertyName,
                     IsStatic = new bool?[] { entity.IsStatic },
                 }
             ), "PropertyName", "Additional"
             );

            // TODO
            rules.Assure(IsFieldObjectInUse).WhenDeleting().AndCanDelete();
        }

        protected virtual ValidationResult IsFieldObjectInUse(TEntity item, out ValidationMessage message)
        {
            if (item.IsStatic)
            {
                message = new ValidationMessage(Str.Messages.ItemIsUsedForEntity4)
                {
                    item,
                    typeof(TBusinessObject).Name,
                    "MetaData",
                    item.PropertyName,
                };
                return ValidationResult.Error;
            }

            var provider = Factory.CreateInstance<IMetaDataProvider<TBusinessObject, int>>();
            var additional = provider
                .GetMetaData()
                .Attributes
                .Single(a => a.IsAdditional)
                .Attributes;

            var fieldAttribute = additional
                .SingleOrDefault(a => a.Name.IsEqual(item.PropertyName))
                ;

            if (fieldAttribute.IsNull())
            {
                message = null;
                return ValidationResult.IsValid;
            }

            message = new ValidationMessage(Str.Messages.ItemIsUsedForEntity4)
                {
                    item,
                    typeof(TBusinessObject).Name,
                    "MetaData",
                    item.PropertyName,
                };
            return ValidationResult.Error;
        }

        protected virtual ValidationResult StringFieldHasLength(TEntity item, out ValidationMessage message)
        {
            message = null;

            var applyRule = item.Is()
                            && item.Type.HasType<string>();

            if (!applyRule)
            {
                return ValidationResult.IsValid;
            }

            var hasStringLength = item.Length.Is()
                                  && item.Length > 0
                ;

            if (hasStringLength)
            {
                return ValidationResult.IsValid;
            }

            message = new ValidationMessage("Field of a 'string' type must have a Length property filled");
            return ValidationResult.Error;
        }

        #region MetaData

        protected override void EnrichMetaDataAttribute(MDAttribute attribute, MetaDataMessage metaData)
        {
            base.EnrichMetaDataAttribute(attribute, metaData);
            if (attribute.Name.IsEqual("IsStatic"))
            {
                attribute.CanEdit = false;
            }
        }

        #endregion MetaData
    }
}